package model.led.sequential;

import static org.junit.Assert.*;

import model.common.LED;
import model.grove.LEDSocket;

import org.junit.Test;

import framework.common.ModelFactory;
import framework.common.MultiSensor;
import framework.common.Sensor;
import framework.common.SensorRequest;
import framework.sequential.*;

public class LEDTest {

	private ModelFactory factory = new ModelFactory();

	public HubServer createHubServer() {
		return (HubServer)factory.getHubServer();
	}

	public DeviceServer createDeviceServer(String name) {
		return (DeviceServer)factory.getDeviceServer(name);
	}

	public Sensor createSensor() {
		return new LEDSocket();
	}

	public Client createClient(String user) {
		return new LEDClient(user);
	}

	/**
	 * 未登録デバイスへアクセスしようとしてエラーになるケース
	 */
	@Test
	public void testLED0a() {
		// Hubサーバを起動する
		HubServer hub = (HubServer)createHubServer();

		// ユーザAがLED0をHubサーバに登録する
		DeviceServer da = createDeviceServer("A'LED0");
		da.setSensor(createSensor());
		da.setHub(hub);
		//da.register("A");
		da.start();

		// Aがクライアントを起動し、LED0に接続する
		Client ca = createClient("A");
		ca.setHub(hub);
		ca.connect(da);

		LED la = (LED)ca;

		// Aの操作
		try {
			la.lightOn();
			fail();
		} catch(RuntimeException e) {
		}
		da.stop();
	}

	/**
	 * 未接続デバイスへアクセスしようとしてエラーになるケース
	 */
	@Test
	public void testLED0b() {
		// Hubサーバを起動する
		HubServer hub = createHubServer();

		// ユーザAがLED0をHubサーバに登録する
		DeviceServer da = createDeviceServer("A'LED0");
		da.setSensor(createSensor());
		da.setHub(hub);
		da.register("A");
		da.start();

		// Aがクライアントを起動し、LED0に接続する
		Client ca = createClient("A");
		ca.setHub(hub);
		//ca.connect(da);

		LED la = (LED)ca;

		// Aの操作
		try {
			la.lightOn();
			fail();
		} catch(RuntimeException e) {
		}
		da.stop();
	}

	/**
	 * センサー未接続のデバイスへアクセスしようとしてエラーになるケース
	 */
	@Test
	public void testLED0c() {
		// Hubサーバを起動する
		HubServer hub = createHubServer();

		// ユーザAがLED0をHubサーバに登録する
		DeviceServer da = createDeviceServer("A'LED0");
		//da.setSensor(createSensor());
		da.setHub(hub);
		da.register("A");
		da.start();

		// Aがクライアントを起動し、LED0に接続する
		Client ca = createClient("A");
		ca.setHub(hub);
		ca.connect(da);

		LED la = (LED)ca;

		// Aの操作
		try {
			la.lightOn();
			fail();
		} catch(RuntimeException e) {
//			e.printStackTrace();
		}
		da.stop();
	}

	/**
	 * 1ユーザが1デバイスにアクセスするケース
	 */
	@Test
	public void testLED1() {
		// Hubサーバを起動する
		HubServer hub = createHubServer();

		// ユーザAがLED0をHubサーバに登録する
		DeviceServer da = createDeviceServer("A'LED0");
		da.setSensor(createSensor());
		da.setHub(hub);
		da.register("A");
		da.start();

		// Aがクライアントを起動し、LED0に接続する
		Client ca = createClient("A");
		ca.setHub(hub);
		ca.connect(da);

		LEDClient la = (LEDClient)ca;

		// Aの操作
		la.lightOn();
		assertTrue(la.isOn());
		la.lightOff();
		assertTrue(la.isOff());

		da.stop();
	}

	/**
	 * 1ユーザが2センサの1デバイスにアクセスするケース
	 */
	@Test
	public void testLED1a() {
		// Hubサーバを起動する
		HubServer hub = createHubServer();

		// センサ
		MultiSensor ms = new MultiSensor();
		ms.attach("a", createSensor());
		ms.attach("b", createSensor());

		// ユーザAがLED0をHubサーバに登録する
		DeviceServer da = createDeviceServer("A'hub");
		da.setSensor(ms);
		da.setHub(hub);
		da.register("A");
		da.start();

		// Aがクライアントを起動し、LED0に接続する
		Client ca = createClient("A");
		ca.setHub(hub);
		ca.connect(da);

		// Aの操作
		ca.begin();
		ca.addRequest(SensorRequest.SET, "a.LED",1);
		ca.end();
		ca.request();
		ca.begin();
		ca.addRequest(SensorRequest.SET, "b.LED",1);
		ca.end();
		ca.request();

		da.stop();
	}

	/**
	 * 1ユーザが2デバイスにアクセスするケース
	 */
	@Test
	public void testLED2() {
		// Hubサーバを起動する
		HubServer hub = createHubServer();

		// ユーザAがLED1をHubサーバに登録する
		DeviceServer d1 = createDeviceServer("A'LED1");
		d1.setSensor(createSensor());
		d1.setHub(hub);
		d1.register("A");
		d1.start();

		// ユーザAがLED2をHubサーバに登録する
		DeviceServer d2 = createDeviceServer("A'LED2");
		d2.setSensor(createSensor());
		d2.setHub(hub);
		d2.register("A");
		d2.start();

		// Aがクライアントを起動し、LED0に接続する
		Client ca = createClient("A");
		ca.setHub(hub);

		// LED1の操作
		ca.connect(d1);
		LED la = (LED)ca;
		la.lightOn();
		la.lightOff();

		// LED2の操作
		ca.connect(d2);
		la.lightOn();
		la.lightOff();

		d1.stop();
		d2.stop();
	}

	/**
	 * 2ユーザがそれぞれ1デバイスにアクセスするケース
	 */
	@Test
	public void testLED3() {
		// Hubサーバを起動する
		HubServer hub = createHubServer();

		// ユーザAがLED1をHubサーバに登録する
		DeviceServer da1 = createDeviceServer("A'LED1");
		da1.setSensor(createSensor());
		da1.setHub(hub);
		da1.register("A");
		da1.start();

		// BさんがLED1をHubサーバに登録する
		DeviceServer db1 = createDeviceServer("B'LED1");
		db1.setSensor(createSensor());
		db1.setHub(hub);
		db1.register("B");
		db1.start();

		// Aがクライアントを起動する
		Client ca = createClient("A");
		ca.setHub(hub);

		// AのLED1の操作
		ca.connect(da1);
		LED la = (LED)ca;
		la.lightOn();
		la.lightOff();

		// Bがクライアントを起動する
		Client cb = createClient("B");
		cb.setHub(hub);

		// BのLED1の操作
		cb.connect(db1);
		LED lb = (LED)cb;
		lb.lightOn();
		lb.lightOff();

		da1.stop();
		db1.stop();
	}

	/**
	 * 2ユーザがそれぞれ2デバイスにアクセスするケース
	 */
	@Test
	public void testLED4() {
		// Hubサーバを起動する
		HubServer hub = createHubServer();

		// ユーザAがLED1をHubサーバに登録する
		DeviceServer da1 = createDeviceServer("A'LED1");
		da1.setSensor(createSensor());
		da1.setHub(hub);
		da1.register("A");
		da1.start();

		// ユーザAがLED2をHubサーバに登録する
		DeviceServer da2 = createDeviceServer("A'LED2");
		da2.setSensor(createSensor());
		da2.setHub(hub);
		da2.register("A");
		da2.start();

		// BさんがLED1をHubサーバに登録する
		DeviceServer db1 = createDeviceServer("B'LED1");
		db1.setSensor(createSensor());
		db1.setHub(hub);
		db1.register("B");
		db1.start();

		// BさんがLED2をHubサーバに登録する
		DeviceServer db2 = createDeviceServer("B'LED2");
		db2.setSensor(createSensor());
		db2.setHub(hub);
		db2.register("B");
		db2.start();

		// Aがクライアントを起動する
		Client ca = createClient("A");
		ca.setHub(hub);

		// Bがクライアントを起動する
		Client cb = createClient("B");
		cb.setHub(hub);

		// AのLED1の操作
		ca.connect(da1);
		LED la = (LED)ca;
		la.lightOn();
		la.lightOff();

		// AのLED2の操作
		ca.connect(da2);
		la.lightOn();
		la.lightOff();

		// BのLED1操作
		cb.connect(db1);
		LED lb = (LED)cb;
		lb.lightOn();
		lb.lightOff();

		// BのLED2操作
		cb.connect(db2);
		lb.lightOn();
		lb.lightOff();

		da1.stop();
		da2.stop();
		db1.stop();
		db2.stop();
	}

}
